(function ( exports ) {

    //region TagProvider

    function TagProvider ( letter ) {
        this.letter = letter;
    }

    TagProvider.prototype = {
        tag: function ( tagName ) {
            return [this.letter, ':', tagName].join('');
        },
        ns: function () {
            return ['xmlns:', this.letter].join('');
        }
    };

    //endregion TagProvider

    //region SerializationContext

    function SerializationContext ( pre ) {
        this.alloc = [];
        this.allocNs = [];
        this.tagProviders = [];
        this.snapshotPoints = [];
        this.parentAttrs = [];
    }

    SerializationContext.prototype = {
        letter: function ( ns ) {
            var ltr, indx;

            if ( typeof ns != 'undefined' ) {
                indx = this.allocNs.indexOf(ns);
                if ( indx >= 0 ) {
                    ltr = this.tagProviders[indx];
                }
            }

            return ltr;
        },
        register: function ( ns ) {
            var hns = COSA.Util.getHashString(ns), avail, tp;

            if ( this.allocNs.indexOf(hns) >= 0 ) {
                throw new Error(COSA.Const.Error.SC_NSALREADYREGISTERED);
            }

            avail = [ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'l'];

            tp = new TagProvider(avail[this.alloc.length]);

            this.tagProviders.push(tp);
            this.alloc.push(avail[this.alloc.length]);
            this.allocNs.push(hns);

            return tp;
        },
        snapshot: function () {
            this.snapshotPoints.push({ alloc: this.alloc.length, parentAttrs: this.parentAttrs.length });
        },
        restore: function () {
            var lng = this.snapshotPoints.pop();
            if ( typeof lng != 'undefined' ) {
                while (this.alloc.length > lng.alloc ) {
                    this.alloc.pop();
                    this.allocNs.pop();
                }

                while (this.parentAttrs.length > lng.parentAttrs ) {
                    this.parentAttrs.pop();
                }
            }
        },
        pushParent: function ( attrName, attrValue ) {
            var attr = {};
            attr[attrName] = attrValue;

            this.parentAttrs.push(attr);
        },
        appendToParent: function ( node ) {
            var stopPoint = 0, attr;
            if ( this.snapshotPoints.length > 0 ) {
                stopPoint = this.snapshotPoints[this.snapshotPoints.length - 1].parentAttrs;
            }
            if ( typeof node.attr == 'undefined' && this.parentAttrs.length > stopPoint ) {
                node.attr = {};
            }
            while ( this.parentAttrs.length > stopPoint ) {
                attr = this.parentAttrs.pop();
                for (var prp in attr) {
                    node.attr[prp] = attr[prp];
                }
            }
        }
    };

    //endregion SerializationContext

    exports.SerializationContext = SerializationContext;

})(COSA);
